package org.nerve.bigFileIO.mysql;

import java.io.*;
import java.sql.Blob;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

/**
 * org.nerve.bigFileIO
 * Created by zengxm on 2016/8/24.
 */
public class MysqlFileExporter extends MysqlConnector{

	protected long limitBegin=0;
	protected long limitLength=100;

	protected String defaultType="txt";
	protected long doneCount;
	protected long size;
	protected String sql;

	public MysqlFileExporter(){}

	public MysqlFileExporter(String url,String user,String password){
		super(url,user,password);
	}

	public long getSize() {
		return size;
	}

	public String getSql() {
		return sql;
	}

	public String getDefaultType() {
		return defaultType;
	}

	public void setDefaultType(String defaultType) {
		this.defaultType = defaultType;
	}

	public long getDoneCount() {
		return doneCount;
	}

	public void export(String outDir) throws SQLException, IOException {
		initConnection();

		sql = "select d.*, m.big_meta_update_time as updateDate from big_data_info as d " +
				"LEFT JOIN big_meta_info as m on d.id = m.big_meta_content order by d.id desc " +
				"limit "+limitBegin+","+limitLength;
		ResultSet rs=connection.createStatement()
				.executeQuery(sql);

		SimpleDateFormat dirFormat=new SimpleDateFormat("yyyy-MM");
		SimpleDateFormat nameFormat=new SimpleDateFormat("yyyyMMdd-HHmmss");

		while (rs.next()){
			int id=rs.getInt("id");
			Blob blob=rs.getBlob("big_content");
			Timestamp updateDate=rs.getTimestamp("updateDate");

			String fileType=IOTool.getFileTypeByInputStream(blob.getBinaryStream());
			String savePath=String.join(
					File.separator, outDir,
					dirFormat.format(updateDate),
					id+"-"+nameFormat.format(updateDate)+"."+(fileType==null?defaultType:fileType));

			boolean done=saveToFile(blob.getBinaryStream(), savePath);

			if(done){
				doneCount++;
//				System.out.println(Thread.currentThread().getName()+": save to "+savePath);
				blob.getBinaryStream().close();
			}
		}
		rs.close();
	}

	public int export(String outDir,String condition) throws SQLException, IOException {
		initConnection();

		ResultSet rs=connection.createStatement()
				.executeQuery("select d.*, m.big_meta_update_time as updateDate from big_data_info as d " +
						"LEFT JOIN big_meta_info as m on d.id = m.big_meta_content WHERE "+(condition==null?"1=1":condition)+" order by d.id desc " +
						"limit "+limitBegin+","+limitLength);

		SimpleDateFormat dirFormat=new SimpleDateFormat("yyyy-MM");
		SimpleDateFormat nameFormat=new SimpleDateFormat("yyyyMMdd-HHmmss");
		int id=0;
		while (rs.next()){
			id=rs.getInt("id");
			Blob blob=rs.getBlob("big_content");
			Timestamp updateDate=rs.getTimestamp("updateDate");

			String fileType=IOTool.getFileTypeByInputStream(blob.getBinaryStream());
			String savePath=String.join(
					File.separator, outDir,
					updateDate==null?"_unknown_date":dirFormat.format(updateDate),
					id+"-"+(updateDate==null?"_unknown_date":nameFormat.format(updateDate))+"."+(fileType==null?defaultType:fileType));

			boolean done=saveToFile(blob.getBinaryStream(), savePath);

			if(done){
				doneCount++;
//				System.out.println(Thread.currentThread().getName()+": save to "+savePath);
				blob.getBinaryStream().close();
			}
		}
		rs.close();

		return id;
	}

	protected boolean saveToFile(InputStream is, String out){
		try {
			File file=new File(out);
			if(!file.getParentFile().exists())
				file.getParentFile().mkdirs();

			OutputStream os=new FileOutputStream(out);
			int b=-1;
			byte[] buffer = new byte[8192];

			while ((b=is.read(buffer,0,buffer.length))!=-1){
				os.write(buffer,0, b);
				size+=b;
			}
			os.flush();
			os.close();

			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}

		return false;
	}


	public long getLimitBegin() {
		return limitBegin;
	}

	public MysqlFileExporter setLimitBegin(long limitBegin) {
		this.limitBegin = limitBegin;
		return this;
	}

	public long getLimitLength() {
		return limitLength;
	}

	public MysqlFileExporter setLimitLength(long limitLength) {
		this.limitLength = limitLength;
		return this;
	}
}
